import 'dart:async';

import 'package:easy_refresh/easy_refresh.dart';
import 'package:equatable/equatable.dart';
import 'package:im_app/im/service/ImMessageSendService.dart';
import 'package:im_app/im/util/CollectionUtil.dart';
import 'package:im_app/im/util/ImageUtil.dart';
import 'package:logger/logger.dart';

import '../../dao/ImGroupDao.dart';
import '../../dao/ImMessageDao.dart';
import '../../dao/ImSessionDao.dart';
import '../../pojo/Enums.dart';
import '../../pojo/ImPojo.dart';
import '../../service/ImMessageReadService.dart';
import '../../service/ImMessageService.dart';
import '../../service/ImSessionService.dart';
import '../../util/DateUtil.dart';
import '../../util/ImConstant.dart';
import '../../util/ImSingleton.dart';
import '../../util/MessageUtil.dart';
import '../../util/Objects.dart';
import '../view/component/audio/Audio2RecordService.dart';
import '../view/component/pane/ImMessageHandler.dart';
import 'BaseBloc.dart';

final class MessageListCubit extends BaseBloc<MessageListEvent, MessageListState> {
  final int sessionId;
  final int? messageId;

  Timer? _myTimer = null;
  Audio2RecordService? _audioRecordService = null;

  MessageListCubit({required this.sessionId, this.messageId }) : super(const MessageListState.loading()) {
    on<MessageListCleanEvent>((event, emit){
      _clean(state);
    });
    on<MessageListAddMessagesEvent>((event, emit){
      _addMessages(state, event.messages);
    });
    on<MessageListUpdateMessagesEvent>((event, emit){
      _updateMessages(state, event.messages);
    });
    on<MessageListRemoveMessagesEvent>((event, emit){
      _removeMessages(state, event.messages);
    });
    on<MessageListCleanMessagesEvent>((event, emit){
      _cleanMessages(state);
    });
    on<MessageListSelectableEvent>((event, emit){
      _selectableMessages(state, event.selectable);
    });
    on<MessageListSelectMessageEvent>((event, emit){
      _selectMessage(state, event.selectMessage, event.isSelected);
    });
    on<MessageListDeleteMessagesEvent>((event, emit){
      _deleteMessages(state);
    });
    on<MessageListCollectMessagesEvent>((event, emit){
      _collectMessages(state);
    });
    on<MessageListUploadProgressEvent>((event, emit){
      _updateUploadProgress(state, event.message, event.progress);
    });
    on<MessageListShowAudioEvent>((event, emit){
      _showAudio(state, event.isAudio);
    });
    on<MessageListSubmitAudioEvent>((event, emit){
      _submitAudio(state);
    });
    on<MessageListLoadDataEvent>((event, emit){
      _loadData(state);
    });
    on<MessageListLoadNewsDataEvent>((event, emit){
      _loadNewsData(state, event.easyRefreshController);
    });
    on<MessageListLoadOldDataEvent>((event, emit){
      _loadOldData(state, event.easyRefreshController);
    });
  }

  final _logger = Logger(printer: PrettyPrinter(),);

  void _updateMessages(MessageListState oldState, List<ImMessage> imMessages) {
    var wrapMessages = _merge(oldState.wrapMessages, imMessages);

    var newState = oldState.copy(wrapMessages: wrapMessages, selectIndex: wrapMessages.length-1);
    emit(newState);
  }

  void _removeMessages(MessageListState oldState, List<ImMessage> imMessages) {
    var wrapMessages = List.of(oldState.wrapMessages);
    for (var imMessage in imMessages) {
      CollectionUtil.delete(wrapMessages, (m)=>m.message.id == imMessage.id);
    }
    emit(oldState.copy(wrapMessages: wrapMessages));
  }

  void _cleanMessages(MessageListState oldState) {
    emit(oldState.copy(wrapMessages: []));
  }

  void _selectableMessages(MessageListState oldState, bool selectable) {
    emit(oldState.copy(selectable: selectable));
  }

  // 选中消息
  void _selectMessage(MessageListState oldState, WrapImMessage wrapImMessage, bool isSelected) {
    // var wrapMessages = List.of(oldState.wrapMessages);
    var selectedMessages = List.of(oldState.selectedMessages);
    wrapImMessage.isSelected = isSelected;
    var wrapMessages = _merge2(selectedMessages, [wrapImMessage]);

    var index = CollectionUtil.indexOf(selectedMessages, (wm)=> wm.message.id == wrapImMessage.message.id);
    if (index >= 0) {
      selectedMessages.removeAt(index);
    } else {
      selectedMessages.add(wrapImMessage);
    }

    emit(oldState.copy(wrapMessages: wrapMessages, selectedMessages: selectedMessages));
  }

  // 删除消息
  void _deleteMessages(MessageListState oldState) async {
    var messageHandler = ImMessageHandler();
    var sessionDao = ImSessionDao();

    var messages = oldState.selectedMessages.map((wm)=>wm.message).toList(growable: false);
    await messageHandler.deleteMessages(messages);

    var session = await sessionDao.getById(sessionId);
    emit(oldState.copy(forwardSession: session, forwardUrl: "/MessageSendPage", businessMsg: '删除消息成功'));
  }

  // 收藏消息
  void _collectMessages(MessageListState oldState) async {
    var messageHandler = ImMessageHandler();
    var sessionDao = ImSessionDao();

    var messages = oldState.selectedMessages.map((wm)=>wm.message).toList();
    var checkCollects = await messageHandler.checkCollectMessages(messages);
    if (checkCollects) {
      emit(oldState.copy(errorMsg: '消息已经收藏, 请不要重复收藏'));
      return;
    }
    await messageHandler.collectMessages(messages);

    var session = await sessionDao.getById(sessionId);
    emit(oldState.copy(forwardSession: session, forwardUrl: "/MessageSendPage", businessMsg: '收藏消息成功'));
  }

  // 更新进度条
  void _updateUploadProgress(MessageListState oldState, ImMessage message, double progress) {
    if (!canShowMessage(message)) return;
    var newWrapMessage = toWrapImMessage(message);
    newWrapMessage.uploadProgress = progress;
    newWrapMessage.status = WrapImMessageStatus.uploading;
    var selectedMessages = List.of(oldState.wrapMessages);
    var wrapMessages = _merge2(selectedMessages, [newWrapMessage]);
    var newState = oldState.copy(wrapMessages: wrapMessages);
    emit(newState);
  }

  void _showAudio(MessageListState oldState, bool isAudio) async {
    var newState = oldState.copy(isAudio: isAudio);
    emit(newState);
    if (isAudio) {
      _audioRecordService = Audio2RecordService();
      _audioRecordService!.startRecord();

      _myTimer = Timer.periodic(const Duration(seconds: 1), (timer) {
        var time = _audioRecordService?.calcAudioTime();
        if (time != null) {
          print("audio time: $time");
          emit(newState.copy(audioTime: time));
        }
      });
    } else {
      await _audioRecordService?.closeRecord();
      if (_myTimer != null) {
        _myTimer!.cancel();
      }
    }
  }

  // 发送语音消息
  void _submitAudio(MessageListState oldState) async {
    await _audioRecordService?.closeRecord();
    if (_myTimer != null) {
      _myTimer!.cancel();
    }
    var time = _audioRecordService!.getAudioTime();
    var audioFile = _audioRecordService!.getAudioFile();

    var messageSendService = ImMessageSendService();
    var sessionDao = ImSessionDao();
    var imSession = await sessionDao.getById(sessionId);
    var message = await messageSendService.buildMessage(imSession!, audioFile!, ImMessageType.Audio, null);
    message.messageExt!.time = time;
    message.init();

    var newState = _addMessages(oldState, [message]);

    if (imSession!.groupCode != null) {
      var groupDao = ImGroupDao();
      var sessionService = ImSessionService();
      imSession.group = await groupDao.getByCodeAndUserId(imSession.groupCode!, imSession.currentUserId!);
      await sessionService.initSessionInfo(imSession);
    }

    ImSingleton.getInstance().sessionListCubit?.changeSession(imSession);

    await messageSendService.sendMessage([imSession], [message]);
    emit(newState.copy(isAudio: false));
  }

  void _updateMessage(List<WrapImMessage> wrapMessages, ImMessage imMessage) {
    WrapImMessage wrapMessage = toWrapImMessage(imMessage);
    // replaceMessage(wrapMessages, wrapMessage);
  }

  bool canShowMessage(ImMessage message) {
    return sessionId == message.sessionId;
  }

  bool notShowMessage(ImMessage message) {
    return sessionId != message.sessionId;
  }

  MessageListState _addMessages(MessageListState oldState, List<ImMessage> imMessages) {
    List<ImMessage> canAddMessages = CollectionUtil.filter(imMessages, canShowMessage);
    if (canAddMessages.isEmpty) return oldState;
    List<WrapImMessage> newWrapMessages = imMessages.map((m)=>toWrapImMessage(m)).toList();
    List<WrapImMessage> wrapMessages = List.of(state.wrapMessages);
    // wrapMessages.insertAll(0, newWrapMessages);
    wrapMessages.addAll(newWrapMessages);
    var newState = oldState.copy(wrapMessages: wrapMessages, selectIndex: wrapMessages.length-1);
    emit(newState);
    return newState;
  }

  void _clean(MessageListState state) {
    emit(state.copy(wrapMessages: []));
  }

  // void replaceMessage(List<WrapImMessage> wrapMessages, WrapImMessage wrapMessage) {
  //   var index = CollectionUtil.indexOf(wrapMessages, (wm)=> wm.message.id == wrapMessage.message.id);
  //   if (index >= 0) {
  //     wrapMessages.replaceRange(index, index+1, [wrapMessage]);
  //   }
  // }

  List<WrapImMessage> _merge(List<WrapImMessage> wrapMessages, List<ImMessage> imMessages) {
    var newWrapMessages = <WrapImMessage>[];
    for (var oldMessage in wrapMessages) {
      bool isHave = false;
      for (var imMessage in imMessages) {
        if (oldMessage.message.id == imMessage.id) {
          isHave = true;
          var wrapMessage = toWrapImMessage(imMessage);
          newWrapMessages.add(wrapMessage);
        }
      }
      if (!isHave) {
        newWrapMessages.add(oldMessage);
      }
    }
    return newWrapMessages;
  }

  List<WrapImMessage> _merge2(List<WrapImMessage> wrapMessages, List<WrapImMessage> imMessages) {
    var newWrapMessages = <WrapImMessage>[];
    for (var oldMessage in wrapMessages) {
      bool isHave = false;
      for (var imMessage in imMessages) {
        if (oldMessage.message.id == imMessage.message.id) {
          isHave = true;
          newWrapMessages.add(imMessage);
          break;
        }
      }
      if (!isHave) {
        newWrapMessages.add(oldMessage);
      }
    }
    return newWrapMessages;
  }

  Future<List<ImMessage>> _loadData(MessageListState oldState) async {
    _logger.i("$sessionId begin load data!");
    List<ImMessage> messages = await loadMessages(sessionId, messageId);
    await handleImageSize(messages);

    var updateExtMessages = await _calcImageSize(messages);
    // int sid = sessionId;
    // List<ImMessage> messages = await IsolatePoolUtil.getInstance().compute(loadMessages, sid);

    var wrapMessages = messages.map((m)=> toWrapImMessage(m)).toList(growable: false);

    _sortImMessages(wrapMessages);        // 排序

    ImMessageReadService messageReadService = ImMessageReadService.getInstance();
    String userId = ImSingleton.getInstance().session.userId!;
    messageReadService.asyHandleReadMessage(sessionId, userId, messages);
    // unawaited(
    //     messageReadService.sendReadMessages(userId, messages)
    // );
    emit(MessageListState.success(wrapMessages, LoadingType.init, wrapMessages.length-1));

    unawaited(batchUpdateMessageExt(userId, updateExtMessages));

    return messages;
  }

  Future<IndicatorResult> _loadNewsData(MessageListState oldState, EasyRefreshController easyRefreshController) async {
    _logger.i("$sessionId begin load news data!");
    var startDate = DateTime.now().add(const Duration(days: -ImConstant.IM_SESSION_SHOW_DAYS));
    if (state.wrapMessages.isNotEmpty) {
      var wrapMessage = state.wrapMessages[state.wrapMessages.length-1];
      startDate = wrapMessage.message.serverReceiveTime??(wrapMessage.message.createTime!);
    }
    _logger.i("$sessionId begin load news data! statTime: ${DateUtil.formatDate(startDate)}");
    List<ImMessage> result = await loadNewsMessages(LoadMessageParam(sessionId: sessionId, startDate: startDate));
    await handleImageSize(result);

    var updateExtMessages = await _calcImageSize(result);

    int oldSize = state.wrapMessages.length;
    if(result.isNotEmpty) {
      var newWrapMessages = result.map((m)=>toWrapImMessage(m)).toList(growable: false);
      List<WrapImMessage> wrapMessages = _mergeMessages(state.wrapMessages, newWrapMessages, true);
      _sortImMessages(wrapMessages);        // 排序

      emit(MessageListState.success(wrapMessages, LoadingType.news, wrapMessages.length - oldSize));

      ImMessageReadService messageReadService = ImMessageReadService.getInstance();
      String userId = ImSingleton.getInstance().session.userId!;

      List<ImMessage> messages = wrapMessages.map((wm)=>wm.message).toList(growable: false);
      messageReadService.asyHandleReadMessage(sessionId, userId, messages);
      unawaited(
          batchUpdateMessageExt(userId, updateExtMessages)
      );
    } else {
      emit(const MessageListState.success([], LoadingType.news, -1));
      easyRefreshController.finishLoad(IndicatorResult.success);
      return IndicatorResult.success;
    }

    easyRefreshController.finishLoad();
    easyRefreshController.resetFooter();
    return IndicatorResult.success;
  }

  Future<IndicatorResult> _loadOldData(MessageListState oldState, EasyRefreshController easyRefreshController) async {
    _logger.i("$sessionId begin load old data!");
    var startDate = DateTime.now().add(const Duration(days: -ImConstant.IM_SESSION_SHOW_DAYS));
    WrapImMessage? firstWrapMessage = null;
    if (state.wrapMessages.isNotEmpty) {
      firstWrapMessage = state.wrapMessages[0];
      startDate = firstWrapMessage.message.serverReceiveTime??(firstWrapMessage.message.createTime!);
    }
    _logger.i("$sessionId begin load old data! statTime: ${DateUtil.formatDate(startDate)}");
    List<ImMessage> result = await loadOldMessages(LoadMessageParam(sessionId: sessionId, startDate: startDate));
    await handleImageSize(result);

    await _calcImageSize(result);

    int oldSize = state.wrapMessages.length;
    if(result.isNotEmpty) {
      var newWrapMessages = result.map((m)=>toWrapImMessage(m)).toList(growable: false);
      List<WrapImMessage> wrapMessages = _mergeMessages(newWrapMessages, state.wrapMessages, false);
      _sortImMessages(wrapMessages);        // 排序

      var selectIndex = 0;
      if (firstWrapMessage != null) {
        selectIndex = wrapMessages.indexWhere((wm)=>wm.message.id == firstWrapMessage!.message!.id);
      }
      easyRefreshController.finishRefresh();
      emit(oldState.copy(wrapMessages: wrapMessages, selectIndex: selectIndex));

      ImMessageReadService messageReadService = ImMessageReadService.getInstance();
      String userId = ImSingleton.getInstance().session.userId!;
      var messages = wrapMessages.map((m)=>m.message).toList(growable: false);
      messageReadService.asyHandleReadMessage(sessionId, userId, messages);
      unawaited(
          batchUpdateMessageExt(userId, messages)
      );
    } else {
      easyRefreshController.finishRefresh();
      emit(MessageListState.success(state.wrapMessages, state.type, oldSize));

      return IndicatorResult.success;
    }
    return IndicatorResult.success;
  }

  Future<void> handleImageSize(List<ImMessage> messages) async {
    var messageService = ImMessageService();
    await messageService.handleImageSize(messages);
  }

  List<WrapImMessage> _mergeMessages(List<WrapImMessage> wrapMessages, List<WrapImMessage> wrapMessages2, bool isNews) {
    List<WrapImMessage> result = List.of(wrapMessages);
    for (var wrapMessage in wrapMessages2) {
      if (!CollectionUtil.contain(result, (m)=>m.message.id == wrapMessage.message.id)) {
        result.add(wrapMessage);
      }
    }
    if (result.length >= ImConstant.MESSAGE_LIST_MAX_SIZE) {
      if (isNews) {
        return result.sublist(result.length - ImConstant.MESSAGE_LIST_MAX_SIZE);
      }
      return result.sublist(0, ImConstant.MESSAGE_LIST_MAX_SIZE);
    }
    return result;
  }

  Future<List<ImMessage>> _calcImageSize(List<ImMessage> messages) async {
    var updateMessages = <ImMessage>[];
    for (ImMessage message in messages) {
      if (message.messageType != ImMessageType.Image) continue;
      message.initMessageExt();
      if (message.messageExt?.imageHeight == null || message.messageExt?.imageWidth == null) {
        if (message.fileStatus == ImMessageFileStatus.downloaded || message.fileStatus == ImMessageFileStatus.uploaded) {
          var imagePath = MessageUtil.getFilePath2(message);
          var size = await ImageUtil.getImageSize(imagePath);
          message.messageExt?.imageWidth = size[0];
          message.messageExt?.imageHeight = size[1];
          message.init();
          updateMessages.add(message);
        }
      }
    }
    return updateMessages;
  }

  void _sortImMessages(List<WrapImMessage> wrapMessages) {
    if (wrapMessages.isEmpty) return;
    wrapMessages.sort((a, b) {
      final DateTime? s1 = a.message.serverReceiveTime;
      final DateTime? s2 = b.message.serverReceiveTime;
      if (s1 == null && s2 == null) {
        return 0;
      }
      if (s1 == null && s2 != null) {
        return -1;
      }
      if (s1 != null && s2 == null) {
        return 1;
      }
      if (s1 != null && s2 != null) {
        var value =  s1!.compareTo(s2!);
        if (value == 0) {
          return (a.message.id??0).compareTo((b.message.id??0));
        }
        return value;
      }
      return 0;
    });
  }
}

Future<List<ImMessage>> loadNewsMessages(LoadMessageParam param) async {
  var messageDao = ImMessageDao();
  List<ImMessage> messages = await messageDao.getNewsBySessionId(param.sessionId, param.startDate, ImConstant.MESSAGE_LIST_DEFAULT_SIZE);
  await messageDao.loadMessageOtherInfo(messages);
  return messages;
}

Future<List<ImMessage>> loadOldMessages(LoadMessageParam param) async {
  var messageDao = ImMessageDao();
  List<ImMessage> messages = await messageDao.getOldBySessionId(param.sessionId, param.startDate, ImConstant.MESSAGE_LIST_DEFAULT_SIZE);
  await messageDao.loadMessageOtherInfo(messages);
  return messages;
}

class LoadMessageParam {
  int sessionId;
  DateTime startDate;

  LoadMessageParam({ required this.sessionId, required this.startDate});
}

Future<List<ImMessage>> loadMessages(int sessionId, int? messageId) async {
  var messageDao = ImMessageDao();
  var date = DateTime.now();
  date = date.add(const Duration(days: -14));
  var pageSize = ImConstant.MESSAGE_LIST_NEXT_SIZE;
  List<ImMessage> messages;
  if (Objects.isNotNull(messageId)) {
    var message = await messageDao.getById(messageId!);
    date = message!.serverReceiveTime!;
    pageSize = 10;
    messages = await messageDao.getNewsBySessionId(sessionId, date, pageSize);
  } else {
    messages = await messageDao.getBySessionId(sessionId, date, pageSize);
  }

  await messageDao.loadMessageOtherInfo(messages);
  return messages;
}

Future<void> batchUpdateMessageExt(String currentUserId, List<ImMessage> messages) async {
  var messageDao = ImMessageDao();
  await messageDao.batchUpdateExts(currentUserId, messages);
}

final class MessageListState extends Equatable {

  final LoadingState state;
  final List<WrapImMessage> wrapMessages;
  final List<WrapImMessage> selectedMessages;
  final LoadingType type;
  final bool selectable;
  final String? forwardUrl;
  final ImSession? forwardSession;
  final String businessMsg;
  final String errorMsg;
  final int selectIndex;
  final bool isAudio;
  final bool isPause;
  final int audioTime;

  const MessageListState._({
    this.state = LoadingState.loading,
    this.wrapMessages = const <WrapImMessage>[],
    this.selectedMessages = const <WrapImMessage>[],
    this.type = LoadingType.init,
    this.selectable = false,
    this.forwardUrl = '',
    this.forwardSession = null,
    this.businessMsg = '',
    this.errorMsg = '',
    this.selectIndex = -1,
    this.isAudio = false,
    this.isPause = false,
    this.audioTime = 0,
  });

  MessageListState copy({List<WrapImMessage>? wrapMessages, LoadingType? type, LoadingState? state,
    bool? selectable, List<WrapImMessage>? selectedMessages, String? forwardUrl,
    ImSession? forwardSession, String? businessMsg, String? errorMsg, int? selectIndex, bool? isAudio,
    bool? isPause, int? audioTime}) {
    return MessageListState._(
      wrapMessages: wrapMessages ?? this.wrapMessages,
      type: type ?? this.type,
      state: this.state,
      selectable: selectable ?? this.selectable,
      selectedMessages: selectedMessages ?? this.selectedMessages,
      forwardUrl: forwardUrl ?? this.forwardUrl,
      forwardSession: forwardSession ?? this.forwardSession,
      businessMsg: businessMsg ?? this.businessMsg,
      errorMsg: errorMsg ?? this.errorMsg,
      selectIndex: selectIndex ?? this.selectIndex,
      isAudio: isAudio ?? this.isAudio,
      isPause: isPause ?? this.isPause,
      audioTime: audioTime ?? this.audioTime,
    );
  }

  const MessageListState.loading() : this._();

  const MessageListState.success(List<WrapImMessage> wrapMessages, LoadingType type, int selectIndex)
      : this._(state: LoadingState.success, wrapMessages: wrapMessages, type: type, selectIndex: selectIndex);

  const MessageListState.failure() : this._(state: LoadingState.failure);

  @override
  List<Object?> get props => [state, wrapMessages, selectedMessages, type, selectable, isAudio, isPause, audioTime];

}

abstract class MessageListEvent {}
final class MessageListCleanEvent extends MessageListEvent {}
final class MessageListAddMessagesEvent extends MessageListEvent {
  final List<ImMessage> messages;
  MessageListAddMessagesEvent(this.messages);
}
final class MessageListUpdateMessagesEvent extends MessageListEvent {
  final List<ImMessage> messages;
  MessageListUpdateMessagesEvent(this.messages);
}
final class MessageListRemoveMessagesEvent extends MessageListEvent {
  final List<ImMessage> messages;
  MessageListRemoveMessagesEvent(this.messages);
}
final class MessageListCleanMessagesEvent extends MessageListEvent {
  MessageListCleanMessagesEvent();
}
final class MessageListSelectableEvent extends MessageListEvent {
  final bool selectable;
  MessageListSelectableEvent(this.selectable);
}
final class MessageListSelectMessageEvent extends MessageListEvent {
  final WrapImMessage selectMessage;
  final bool isSelected;
  MessageListSelectMessageEvent(this.selectMessage, this.isSelected);
}
final class MessageListDeleteMessagesEvent extends MessageListEvent {
  MessageListDeleteMessagesEvent();
}
final class MessageListCollectMessagesEvent extends MessageListEvent {
  MessageListCollectMessagesEvent();
}
final class MessageListUploadProgressEvent extends MessageListEvent {
  double progress;
  ImMessage message;
  MessageListUploadProgressEvent(this.message, this.progress);
}
final class MessageListShowAudioEvent extends MessageListEvent {
  final bool isAudio;
  MessageListShowAudioEvent(this.isAudio);
}
final class MessageListSubmitAudioEvent extends MessageListEvent {
  MessageListSubmitAudioEvent();
}
final class MessageListLoadDataEvent extends MessageListEvent {
  MessageListLoadDataEvent();
}
final class MessageListLoadNewsDataEvent extends MessageListEvent {
  EasyRefreshController easyRefreshController;
  MessageListLoadNewsDataEvent(this.easyRefreshController);
}
final class MessageListLoadOldDataEvent extends MessageListEvent {
  EasyRefreshController easyRefreshController;
  MessageListLoadOldDataEvent(this.easyRefreshController);
}

final class WrapImMessage extends Equatable {
  ImMessage message;
  WrapImMessageStatus status;
  String statusFile;
  bool isSelected;
  double uploadProgress = 0;
  double downloadProgress = 0;
  String content;       // 消息内容，当消息带有附件时，内容会变更

  WrapImMessage(this.message, this.status, this.statusFile, this.isSelected, this.content);

  @override
  List<Object?> get props => [status, statusFile, message, isSelected, uploadProgress, downloadProgress, content];
}

WrapImMessage toWrapImMessage(ImMessage message) {
  var wrapImMessageStatus = calcMessageStatus(message);
  var statusFile = toStatusFile(wrapImMessageStatus);
  var wrapMessage = WrapImMessage(message, wrapImMessageStatus, statusFile, false, message.content);
  return wrapMessage;
}

WrapImMessageStatus calcMessageStatus(ImMessage message) {
  ImMessageStatus? status = message.status;
  ImMessageActionStatus actionStatus = message.actionStatus ?? ImMessageActionStatus.none;

  if (actionStatus!.isWithdraw()) return WrapImMessageStatus.empty;
  if (status!.isWithdraw()) return WrapImMessageStatus.empty;
  if (status == ImMessageStatus.failure) return WrapImMessageStatus.no_send;
  if (status == ImMessageStatus.sending) return WrapImMessageStatus.sending;

  if (status == ImMessageStatus.created && DateUtil.hasExceededTime(message.createTime!, 1)) {
    return WrapImMessageStatus.no_send;
  } else if (status == ImMessageStatus.created && !DateUtil.hasExceededTime(message.createTime!, 1)) {
    return WrapImMessageStatus.empty;
  } else if (status == ImMessageStatus.sended) {
    // 发送成功
    WrapImMessageStatus? wrapImMessageStatus = null;
    if (message.isAttachFile()) {
      wrapImMessageStatus = toWrapImMessageFileStatus(message);
    }
    if (wrapImMessageStatus == null || wrapImMessageStatus == WrapImMessageStatus.empty) {
      if (actionStatus != ImMessageActionStatus.readed) {
        return WrapImMessageStatus.no_read;
      } else {
        return WrapImMessageStatus.empty;
      }
    } else {
      return wrapImMessageStatus;
    }
  } else if (status == ImMessageStatus.ref) {
    // 发送成功
    return WrapImMessageStatus.no_read;
  }
  return WrapImMessageStatus.empty;
}

WrapImMessageStatus toWrapImMessageFileStatus(ImMessage imMessage) {
  String userId = ImSingleton.getInstance().session.userId!;
  ImMessageFileStatus? fileStatus = imMessage.fileStatus;
  DateTime localDateTime = imMessage.createTime!;
  int sendTime = ImConstant.Message_FileSendTime;
  if (fileStatus == null) {
    return WrapImMessageStatus.no_upload;
  }
  if (fileStatus == ImMessageFileStatus.created && DateUtil.hasExceededTime(localDateTime, sendTime)) {
    return WrapImMessageStatus.no_upload;
  } else if (fileStatus == ImMessageFileStatus.created && !DateUtil.hasExceededTime(localDateTime, sendTime)) {
    return WrapImMessageStatus.empty;
  } else if (fileStatus == ImMessageFileStatus.uploading) {
    return WrapImMessageStatus.uploading;
  } else if (fileStatus == ImMessageFileStatus.uploaded) {
    return WrapImMessageStatus.empty;
  } else if (fileStatus == ImMessageFileStatus.downloading) {
    return WrapImMessageStatus.downloading;
  } else if (fileStatus == ImMessageFileStatus.downloaded) {
    return WrapImMessageStatus.empty;
  } else if (fileStatus == ImMessageFileStatus.none && imMessage.fromUserId != userId) {
    return WrapImMessageStatus.no_download;
  } else if (fileStatus == ImMessageFileStatus.empty) {
    return WrapImMessageStatus.uploading;
  } else if (fileStatus == ImMessageFileStatus.none) {
    return WrapImMessageStatus.empty;
  }
  throw Exception("不支持这种类型2 ${fileStatus.name}");
}

String toStatusFile(WrapImMessageStatus status) {
  String assetFile = "";
  if (status == WrapImMessageStatus.no_send) {
    assetFile = "assets/img/no_send.png";
  } else if (status == WrapImMessageStatus.no_read) {
    assetFile = "assets/img/no_read.png";
  } else if (status == WrapImMessageStatus.no_upload) {
    assetFile = "assets/img/no_upload.png";
  } else if (status == WrapImMessageStatus.no_download) {
    assetFile = "assets/img/no_download.png";
  } else if (status == WrapImMessageStatus.sending) {
    assetFile = "assets/img/loading.gif";
  }
  return assetFile;
}

enum WrapImMessageStatus {
  no_send,
  no_read,
  no_upload,
  no_download,
  empty,
  sending,
  uploading,
  downloading,
}
